package github.leavesczy.reactivehttpsamples.ui.main

import android.annotation.SuppressLint
import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.blankj.utilcode.constant.PermissionConstants
import com.blankj.utilcode.util.PermissionUtils
import com.blankj.utilcode.util.StringUtils
import github.leavesczy.reactivehttpsamples.R
import github.leavesczy.reactivehttpsamples.base.BaseFragment
import github.leavesczy.reactivehttpsamples.core.mode.SensorLocation
import github.leavesczy.reactivehttpsamples.core.viewmodel.main.HomeViewModel
import github.leavesczy.reactivehttpsamples.databinding.FragmentHomeBinding
import github.leavesczy.reactivehttpsamples.util.AccelerometerSimpleRate
import github.leavesczy.reactivehttpsamples.util.DateHelper
import github.leavesczy.reactivehttpsamples.util.FileUtilHelper
import github.leavesczy.reactivehttpsamples.util.Logger
import github.leavesczy.reactivehttpsamples.util.PermissionHelper
import github.leavesczy.reactivehttpsamples.util.SensorLocationLineChart
import github.leavesczy.reactivehttpsamples.widget.dialog.BridgeFileNameDialog
import github.leavesczy.reactivehttpsamples.widget.dialog.BridgeFileNameDialog.Callback
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.util.Timer
import java.util.TimerTask


class HomeFragment : BaseFragment() {
    companion object {
        fun newInstance(): Fragment {
            val fragment = HomeFragment()
            val bundle = Bundle()
            fragment.arguments = bundle
            return fragment
        }
    }

    private var bind: FragmentHomeBinding? = null

    private val mBind: FragmentHomeBinding get() = bind!!

    private var sensor: Sensor? = null
    private var sensorManager: SensorManager? = null

    private var locationManager: LocationManager? = null

    private lateinit var sensorLocationLineChart: SensorLocationLineChart

    //样本类型 0-连续行车 1-跨中停车
    private var sampleType: Int = 0

    private val viewModel by getViewModel<HomeViewModel>() {
        //上传文件
        addMeasureModelData.observe(viewLifecycleOwner) {
            //上传成功
            showToast("上传成功")
        }

        //请求当前编码的文件数量
        getMeasureModelNumData.observe(viewLifecycleOwner) {
            mBind.tvMeasureNum.text = it.getNumStr()
        }
        //请求当前 编号的编码
        measureFileSerialNumData.observe(viewLifecycleOwner) {
            showDialogConfirmFileName(it.getNumStr())
        }
    }

    private val mDataList = mutableListOf<SensorLocation>()

    private var currentFile: File? = null

    private var bridgeCode: String? = null
    private var bridgeName: String? = null

    private var timer: Timer? = null

    private var startTimeMillis: Long? = null

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        bind = FragmentHomeBinding.inflate(inflater, container, false)
        return mBind.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initListener()
        initSensor()
        initLineChart()
        //提前注册 监听定位
        registerLocationListener()
    }

    private fun registerLocationListener() {
        //先注销掉之前的监听
        unregisterLocationListener()
        //再重新 申请权限，然后注册监听
        PermissionHelper.request(context!!, object : PermissionUtils.SimpleCallback {
            @SuppressLint("MissingPermission")
            override fun onGranted() {
                //开始 先开始定位更新，这样子就能获取定位的数据，定位开启后再开启 传感器
                locationManager?.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER,
                    100L,
                    1f,
                    locationListener
                )
                locationManager?.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER,
                    100L,
                    1f,
                    locationListener
                )
            }

            override fun onDenied() {
                showToast("权限未同意，无法使用当前功能，请重试")
            }
        }, PermissionConstants.LOCATION)


    }

    private fun unregisterLocationListener() {
        locationManager?.removeUpdates(locationListener)
    }

    private fun initLineChart() {

        val lineChart = mBind.lineChart
        sensorLocationLineChart = SensorLocationLineChart(lineChart)
        //设置最大数据量
        sensorLocationLineChart.setMaxPoint(1000)
        sensorLocationLineChart.initLineData()
    }

    private fun startTimer() {
        mBind.tvDataNum.text = "00:00:00"
        mBind.tvDataNum.tag = 0L
        timer?.cancel()

        timer = Timer()
        timer?.schedule(object : TimerTask() {
            override fun run() {
                lifecycleSupportedScope.launch(Dispatchers.Main.immediate) {
                    var timeLength = mBind.tvDataNum.tag as Long
                    timeLength += 1000
                    mBind.tvDataNum.text = DateHelper.convertMillis2TimeFormat(timeLength)
                    mBind.tvDataNum.tag = timeLength

                    getDataBatchAdd()
                }
            }
        }, 1000, 1000)
    }

    private fun stopTimer() {
        timer?.cancel()
        timer = null
    }


    private fun initListener() {
        mBind.tvRefreshMeasureNum.setOnClickListener {
            //刷新当前的 采集样本
            val bridgeCode = mBind.etBridgeCode.editTextStr
            if (StringUtils.isEmpty(bridgeCode)) {
                showToast("请先输入桥梁编码")
                return@setOnClickListener
            }
            viewModel.requestRefreshMeasureNum(bridgeCode)
        }

        mBind.btnStart.setOnClickListener {
            //需要权限
            if (null == currentLocation) {
                showToast("定位无法获取，请同意授权后重试开始收集")
                registerLocationListener()
                return@setOnClickListener
            }

            //开始 先开始定位更新，这样子就能获取定位的数据，定位开启后再开启 传感器
            registerSensor()
        }

        mBind.btnEnd.setOnClickListener {
            //暂停
            unregisterSensor()

            dealCoopStatus(2)
        }

        mBind.btnUpload.setOnClickListener {
            if (currentFile == null) {
                return@setOnClickListener
            }
            val bridgeCode = mBind.etBridgeCode.editTextStr
            if (StringUtils.isEmpty(bridgeCode)) {
                showToast("请先输入桥梁编码")
                return@setOnClickListener
            }
            viewModel.requestMeasureFileSerialNum(bridgeCode, sampleType)
        }

        mBind.btnReset.setOnClickListener {
            dealCoopStatus(4)
        }

        //测试样本类型
        mBind.rgSampleType.setOnCheckedChangeListener { group, checkedId ->
            if (checkedId == R.id.rbSampleType0) {
                sampleType = 0
            } else if (checkedId == R.id.rbSampleType1) {
                sampleType = 1
            }
        }
    }

    private fun showDialogConfirmFileName(serialNum: String) {
        //当前文件的临时名称
        var currentFileName = "${bridgeCode}_sample_${serialNum}.csv"
        if (sampleType == 1) {
            currentFileName = "${bridgeCode}_park_sample_${serialNum}.csv"
        }
        //弹框 确认文件名
        BridgeFileNameDialog().init(requireContext(), currentFileName, object : Callback {
            override fun ok(fileName: String) {
                doSomething(block = {
                    dealUpload(fileName)
                })
            }

            override fun cancel() {

            }
        }).show("BridgeFileNameDialog")
    }

    private suspend fun dealUpload(fileName: String) {
        //把数据写入本地文件
        try {
            showLoading("保存文件中，请等待~", false)
            Logger.d("writerCsv---开始")
            withContext(Dispatchers.IO) {
                Logger.d("writerCsv---异步协程内，开始处理：" + Thread.currentThread().name)
                FileUtilHelper.writerCsv(currentFile!!, mDataList)
            }
            Logger.d("writerCsv---完成：" + currentFile!!.absolutePath)
            dismissLoading()
            // 上产文件
            viewModel.uploadFile(currentFile!!, fileName, bridgeCode!!, bridgeName!!, sampleType)
        } catch (e: Exception) {
            Logger.e("writerCsv---异常：", e)
            dismissLoading()
        } finally {
            Logger.d("writerCsv---结束")
            dealCoopStatus(3)
        }
    }

    private fun initSensor() {
        sensorManager = (context!!.getSystemService(Context.SENSOR_SERVICE) as SensorManager)
        sensor = sensorManager?.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
        locationManager = context!!.getSystemService(Context.LOCATION_SERVICE) as LocationManager

    }

    @SuppressLint("MissingPermission")
    private fun registerSensor() {
        //创建一个 csv文件
        bridgeCode = mBind.etBridgeCode.editTextStr
        if (StringUtils.isEmpty(bridgeCode)) {
            showToast("请输入桥梁编码")
            return
        }
        bridgeName = mBind.etBridgeName.editTextStr
        if (StringUtils.isEmpty(bridgeCode)) {
            showToast("请输入桥梁名称")
            return
        }
        currentFile = FileUtilHelper.createCsvFile(bridgeCode!!)
        if (null == currentFile) {
            showToast("文件创建失败，请重试")
            return
        }

        dealCoopStatus(1)

        sensorManager?.registerListener(
            sensorEventListener,
            sensor!!,
            AccelerometerSimpleRate.getHz100()
        )
    }

    private var currentLocation: Location? = null
    private val locationListener: LocationListener = object : LocationListener {
        override fun onLocationChanged(location: Location) {
            Logger.d("LocationListener  onLocationChanged-->latitude:" + location.latitude + " ;longitude:" + location.longitude)
            currentLocation = location
            //直接展示 定位信息
            dealLocationShow(location)
        }

        override fun onProviderDisabled(provider: String) {
            super.onProviderDisabled(provider)
            Logger.d("LocationListener  onProviderDisabled-->provider:" + provider)
        }

        override fun onProviderEnabled(provider: String) {
            super.onProviderEnabled(provider)
            Logger.d("LocationListener  onProviderEnabled-->provider:" + provider)
        }

        override fun onFlushComplete(requestCode: Int) {
            super.onFlushComplete(requestCode)
            Logger.d("LocationListener  onFlushComplete-->requestCode:" + requestCode)
        }

    }

    private val sensorEventListener: SensorEventListener = object : SensorEventListener {
        @SuppressLint("MissingPermission")
        override fun onSensorChanged(event: SensorEvent) {
            val xAxis = event.values.get(0)
            val yAxis = event.values.get(1)
            val zAxis = event.values.get(2)
            //locationManager?.let {
            // val location = it.getLastKnownLocation(LocationManager.GPS_PROVIDER)
            currentLocation?.let {
                val timeMillis = System.currentTimeMillis()
                val item = SensorLocation(
                    timeMillis,
                    timeMillis - startTimeMillis!!,
                    DateHelper.format2String(timeMillis),
                    getValueByG(xAxis),
                    getValueByG(yAxis),
                    getValueByG(zAxis),
                    it.latitude,
                    it.longitude
                )
                mDataList.add(item)
                //展示有多少数据样本
                // dealSensorDataAdd(item)
            }


            // }

        }

        override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        }
    }

    private fun getValueByG(input: Float): Float {
        return (input / 9.8).toFloat()
    }

    private fun dealSensorDataAdd(item: SensorLocation) {
        sensorLocationLineChart.addData(item)

    }

    var lastDataIndex = 0
    private fun getDataBatchAdd() {
        if (mDataList.size > lastDataIndex) {
//            Logger.d("getDataBatchAdd--size:${mDataList.size},lastDataIndex:${lastDataIndex}")
            sensorLocationLineChart.addDataBatch(mDataList.subList(lastDataIndex, mDataList.size))
            lastDataIndex = mDataList.size
        }
    }

    private fun dealLocationShow(location: Location) {
        mBind.tvLatitude.text = location.latitude.toString()
        mBind.tvLongitude.text = location.longitude.toString()
    }

    fun unregisterSensor() {
        sensorManager?.unregisterListener(sensorEventListener, sensor!!)
    }

    private fun dealCoopStatus(state: Int) {
        when (state) {
            1 -> {
                //点击了 开始
                //停止按钮不可用
                mBind.btnStart.isEnabled = false
                mBind.btnEnd.isEnabled = true
                mBind.btnUpload.isEnabled = false

                mBind.tvCurrentStatus.text = "数据采集中"

                mDataList.clear()
                lastDataIndex=0

                startTimeMillis = System.currentTimeMillis()
                sensorLocationLineChart.initNoData()

                startTimer()
            }

            2 -> {
                //点击了 结束
                //停止按钮不可用
                mBind.btnStart.isEnabled = false
                mBind.btnEnd.isEnabled = false
                mBind.btnUpload.isEnabled = true

                mBind.tvCurrentStatus.text = "数据待上传"

                stopTimer()
            }

            3 -> {
                //点击了 结束上传 操作
                mBind.btnStart.isEnabled = true
                mBind.btnEnd.isEnabled = false
                mBind.btnUpload.isEnabled = false

                mBind.tvCurrentStatus.text = "数据采集待开始"

                mDataList.clear()
                lastDataIndex=0

                currentFile = null
                bridgeCode = null
                bridgeName = null
            }

            4 -> {
                //点击了 重置
                mBind.btnStart.isEnabled = true
                mBind.btnEnd.isEnabled = false
                mBind.btnUpload.isEnabled = false
                mBind.tvCurrentStatus.text = "数据采集待开始"
                mBind.tvDataNum.text = "00:00:00"
                mDataList.clear()
                lastDataIndex=0

                currentFile = null
                bridgeCode = null
                bridgeName = null

                stopTimer()

                sensorLocationLineChart.initNoData()


            }
        }

    }


    override fun onDestroyView() {
        super.onDestroyView()
        unregisterLocationListener()
        bind = null
    }

    override fun onDestroy() {
        super.onDestroy()
    }

    private fun doSomething(block: suspend CoroutineScope.() -> Unit) {
        lifecycleScope.launch {
            Logger.d("doSomething---协程，开始：" + Thread.currentThread().name)
            block()
            Logger.d("doSomething---协程，结束：" + Thread.currentThread().name)
        }
    }

}


